<template>
  <div class="analysis-container">
    <!-- 页面标题区域 -->
    <div class="page-header">
      <div class="header-content">
        <h1 class="page-title">音乐数据概览</h1>
        <p class="page-description">查看音乐播放统计、趋势分析和热门内容数据</p>
      </div>
      <div class="page-actions">
        <el-button type="primary" size="large" @click="exportReport">
          <el-icon><Download /></el-icon> 导出报表
        </el-button>
        <el-button size="large" @click="fetchMusicData">
          <el-icon><RefreshRight /></el-icon> 刷新
        </el-button>
      </div>
    </div>
    
    <!-- 筛选器卡片 -->
    <div class="row-container">
      <el-card class="filter-card">
        <template #header>
          <div class="card-header">
            <span class="card-title">数据筛选</span>
          </div>
        </template>
        <div class="filter-content">
          <div class="filter-item">
            <span class="filter-label">时间范围:</span>
            <el-select v-model="days" placeholder="选择时间范围" size="default" class="filter-select" @change="handleTimeRangeChange">
              <el-option label="近7天" :value="7"></el-option>
              <el-option label="近30天" :value="30"></el-option>
              <el-option label="近90天" :value="90"></el-option>
            </el-select>
          </div>
        </div>
      </el-card>
    </div>
    
    <!-- 数据卡片 -->
    <div class="section-divider">
      <div class="divider-line"></div>
      <div class="divider-text">数据概览</div>
      <div class="divider-line"></div>
    </div>
    
    <div class="row-container">
      <el-row :gutter="20">
        <el-col :span="8">
          <el-card class="data-card" shadow="hover">
            <div class="card-header">
              <div class="card-title">总播放量</div>
            </div>
            <div class="card-value">{{ musicData.total_plays || 0 }}</div>
            <div class="card-footer">过去{{ queryParams.days }}天播放总数</div>
          </el-card>
        </el-col>
        
        <el-col :span="8">
          <el-card class="data-card" shadow="hover">
            <div class="card-header">
              <div class="card-title">不同曲目数</div>
            </div>
            <div class="card-value">{{ musicData.unique_songs || 0 }}</div>
            <div class="card-footer">过去{{ queryParams.days }}天不同曲目数量</div>
          </el-card>
        </el-col>
        
        <el-col :span="8">
          <el-card class="data-card" shadow="hover">
            <div class="card-header">
              <div class="card-title">平均每日播放</div>
            </div>
            <div class="card-value">{{ calculateDailyAverage() }}</div>
            <div class="card-footer">过去{{ queryParams.days }}天平均每日播放量</div>
          </el-card>
        </el-col>
      </el-row>
    </div>
    
    <!-- 图表区域 -->
    <div class="section-divider">
      <div class="divider-line"></div>
      <div class="divider-text">数据可视化</div>
      <div class="divider-line"></div>
    </div>
    
    <div class="row-container chart-row">
      <el-row :gutter="20">
        <el-col :span="12">
          <el-card class="chart-card" shadow="hover">
            <template #header>
              <div class="card-header">
                <div class="card-title">播放趋势分析</div>
                <div class="card-actions">
                  <el-button size="small" @click="fetchMusicData">
                    <el-icon><RefreshRight /></el-icon> 刷新
                  </el-button>
                </div>
              </div>
            </template>
            <div class="chart-wrapper">
              <canvas ref="trendChart"></canvas>
            </div>
          </el-card>
        </el-col>
        
        <el-col :span="12">
          <el-card class="chart-card" shadow="hover">
            <template #header>
              <div class="card-header">
                <div class="card-title">热门艺术家</div>
                <div class="card-actions">
                  <el-button size="small" @click="fetchMusicData">
                    <el-icon><RefreshRight /></el-icon> 刷新
                  </el-button>
                </div>
              </div>
            </template>
            <div class="chart-wrapper">
              <canvas ref="artistChart"></canvas>
            </div>
          </el-card>
        </el-col>
      </el-row>
    </div>
    
    <!-- 表格区域 -->
    <div class="section-divider">
      <div class="divider-line"></div>
      <div class="divider-text">热门歌曲分析</div>
      <div class="divider-line"></div>
    </div>
    
    <div class="row-container">
      <el-card class="table-card" shadow="hover">
        <template #header>
          <div class="card-header">
            <div class="card-title">热门歌曲</div>
            <div class="card-actions">
              <el-button size="small" @click="fetchMusicData">
                <el-icon><RefreshRight /></el-icon> 刷新
              </el-button>
            </div>
          </div>
        </template>
        
        <el-table 
          :data="musicData.top_songs || []" 
          style="width: 100%"
          :header-cell-style="{backgroundColor: '#f5f7fa', color: '#303133', fontWeight: '600'}"
          border
          stripe
        >
          <el-table-column prop="song_name" label="歌曲名称" min-width="200">
            <template #default="{ row }">
              <div class="song-name-cell">
                <div class="song-name">{{ row.song_name }}</div>
              </div>
            </template>
          </el-table-column>
          <el-table-column label="艺术家" min-width="180">
            <template #default="{ row }">
              <div class="artist-cell">
                {{ row.artist }}
              </div>
            </template>
          </el-table-column>
          <el-table-column prop="play_count" label="播放次数" width="160">
            <template #default="{ row }">
              <div class="play-count-cell">
                <el-tag size="default" effect="plain" type="primary" class="play-count-tag">{{ row.play_count }} 次</el-tag>
              </div>
            </template>
          </el-table-column>
        </el-table>
      </el-card>
    </div>
    
    <!-- 浮动操作区 -->
    <div class="floating-actions">
      <el-button type="primary" @click="fetchMusicData" :loading="loading" class="refresh-btn">
        <el-icon><RefreshRight /></el-icon>
      </el-button>
    </div>
    
    <!-- 底部安全区域 -->
    <div class="bottom-safe-area"></div>
  </div>
</template>

<script>
import Chart from 'chart.js/auto'
import axios from 'axios'
import { Download, RefreshRight } from '@element-plus/icons-vue'
import * as XLSX from 'xlsx'

export default {
  name: 'AnalysisPage',
  components: {
    Download,
    RefreshRight,
  },
  data() {
    return {
      days: 30,
      loading: false,
      queryParams: {
        days: 30
      },
      musicData: {
        daily_trend: [],
        top_artists: [],
        top_songs: [],
        total_plays: 0,
        unique_songs: 0
      },
      charts: {
        trend: null,
        artist: null
      },
      chartInitTimer: null,
      previousData: {
        top_artists: null,
        daily_trend: null
      }
    }
  },
  mounted() {
    this.fetchMusicData()
  },
  beforeUnmount() {
    // 组件销毁前清理图表实例和定时器
    this.cleanupCharts();
  },
  methods: {
    cleanupCharts() {
      // 清理图表实例
      if (this.charts.trend) {
        try {
          this.charts.trend.destroy();
        } catch (e) {
          console.error('销毁趋势图表失败:', e);
        }
        this.charts.trend = null;
      }
      
      if (this.charts.artist) {
        try {
          this.charts.artist.destroy();
        } catch (e) {
          console.error('销毁艺术家图表失败:', e);
        }
        this.charts.artist = null;
      }
      
      // 清理定时器
      if (this.chartInitTimer) {
        clearTimeout(this.chartInitTimer);
        this.chartInitTimer = null;
      }
    },
    async fetchMusicData() {
      this.loading = true;
      try {
        const response = await axios.get(`https://smartsound.top/api/v1/admin/music_overview?days=${this.queryParams.days}`)
        if (response.data && response.data.code === 0) {
          // Initialize default data structure, avoid undefined errors
          const defaultData = {
            daily_trend: [],
            top_artists: [],
            top_songs: [],
            total_plays: 0,
            unique_songs: 0
          };

          // Merge API returned data with default data
          const processedData = { 
            ...defaultData,
            ...response.data.data 
          };
          
          // Ensure key array fields exist
          if (!Array.isArray(processedData.daily_trend)) processedData.daily_trend = [];
          if (!Array.isArray(processedData.top_artists)) processedData.top_artists = [];
          if (!Array.isArray(processedData.top_songs)) processedData.top_songs = [];
          
          // Process top artist data
          if (processedData.top_artists && processedData.top_artists.length > 0) {
            processedData.top_artists = processedData.top_artists.map(artist => {
              if (!artist) return null; // Skip empty records
              
              const processedArtist = { ...artist };
              
              // Handle various format situations
              try {
                // Case 1: artist is a JSON string - with single quotes {'id': 11127, 'name': 'Beyond'}
                if (typeof processedArtist.artist === 'string') {
                  // Handle single quote JSON format
                  const trimmed = processedArtist.artist.trim();
                  if (trimmed.startsWith("{") && trimmed.includes("'name'") && trimmed.includes(":")) {
                    // Extract name using regex
                    const nameMatch = trimmed.match(/'name'\s*:\s*'([^']+)'/);
                    if (nameMatch && nameMatch[1]) {
                      processedArtist.artist = nameMatch[1];
                    }
                  }
                  // Direct match for the entire string format {'id': 11127, 'name': 'Beyond'}
                  else if (trimmed.match(/^\{'id': \d+, 'name': '[^']+'\}$/)) {
                    const nameMatch = trimmed.match(/'name': '([^']+)'/);
                    if (nameMatch && nameMatch[1]) {
                      processedArtist.artist = nameMatch[1];
                    }
                  }
                  // Handle double quote JSON format
                  else if (trimmed.startsWith('{') && trimmed.includes('"name"') && trimmed.endsWith('}')) {
                    try {
                      const parsedArtist = JSON.parse(trimmed);
                      if (parsedArtist && parsedArtist.name) {
                        processedArtist.artist = parsedArtist.name;
                      }
                    } catch (parseError) {
                      console.log('JSON parsing failed, extracting with regex:', trimmed);
                      const nameMatch = trimmed.match(/"name"\s*:\s*"([^"]+)"/);
                      if (nameMatch && nameMatch[1]) {
                        processedArtist.artist = nameMatch[1];
                      }
                    }
                  }
                } 
                // Case 2: artist is an object
                else if (typeof processedArtist.artist === 'object' && processedArtist.artist !== null) {
                  processedArtist.artist = processedArtist.artist.name || '';
                }
              } catch (e) {
                console.error('Error processing artist data:', e);
                // Keep original value or set default
                if (!processedArtist.artist) processedArtist.artist = '未知艺术家';
              }
              
              // Ensure play_count is a number
              if (typeof processedArtist.play_count !== 'number') {
                processedArtist.play_count = parseInt(processedArtist.play_count || '0', 10) || 0;
              }
              
              return processedArtist;
            }).filter(item => item !== null); // Filter out null records
          }
          
          // Process top songs data - similar handling for single quote JSON format
          if (processedData.top_songs && processedData.top_songs.length > 0) {
            processedData.top_songs = processedData.top_songs.map(song => {
              if (!song) return null; // Skip empty records
              
              const processedSong = { ...song };
              
              try {
                if (typeof processedSong.artist === 'string') {
                  // Handle single quote JSON format
                  const trimmed = processedSong.artist.trim();
                  if (trimmed.startsWith("{") && trimmed.includes("'name'") && trimmed.includes(":")) {
                    const nameMatch = trimmed.match(/'name'\s*:\s*'([^']+)'/);
                    if (nameMatch && nameMatch[1]) {
                      processedSong.artist = nameMatch[1];
                    }
                  }
                  // Direct match for the entire string format {'id': 11127, 'name': 'Beyond'}
                  else if (trimmed.match(/^\{'id': \d+, 'name': '[^']+'\}$/)) {
                    const nameMatch = trimmed.match(/'name': '([^']+)'/);
                    if (nameMatch && nameMatch[1]) {
                      processedSong.artist = nameMatch[1];
                    }
                  }
                  // Handle double quote JSON format
                  else if (trimmed.startsWith('{') && trimmed.includes('"name"') && trimmed.endsWith('}')) {
                    try {
                      const parsedArtist = JSON.parse(trimmed);
                      if (parsedArtist && parsedArtist.name) {
                        processedSong.artist = parsedArtist.name;
                      }
                    } catch (parseError) {
                      const nameMatch = trimmed.match(/"name"\s*:\s*"([^"]+)"/);
                      if (nameMatch && nameMatch[1]) {
                        processedSong.artist = nameMatch[1];
                      }
                    }
                  }
                } 
                else if (typeof processedSong.artist === 'object' && processedSong.artist !== null) {
                  processedSong.artist = processedSong.artist.name || '';
                }
                
                // Ensure properties exist
                if (!processedSong.song_name) processedSong.song_name = '未知歌曲';
                if (!processedSong.artist) processedSong.artist = '未知艺术家';
                
                // Ensure play_count is a number
                if (typeof processedSong.play_count !== 'number') {
                  processedSong.play_count = parseInt(processedSong.play_count || '0', 10) || 0;
                }
              } catch (e) {
                console.error('Error processing song artist data:', e);
                // Set default value
                if (!processedSong.artist) processedSong.artist = '未知艺术家';
              }
              
              return processedSong;
            }).filter(item => item !== null); // Filter out null records
          }
          
          // Process daily trend data
          if (processedData.daily_trend && processedData.daily_trend.length > 0) {
            processedData.daily_trend = processedData.daily_trend.map(item => {
              if (!item) return null;
              
              const processedItem = { ...item };
              
              // Ensure date field exists
              if (!processedItem.date) {
                processedItem.date = '未知日期';
              }
              
              // Ensure play_count is a number
              if (typeof processedItem.play_count !== 'number') {
                processedItem.play_count = parseInt(processedItem.play_count || '0', 10) || 0;
              }
              
              return processedItem;
            }).filter(item => item !== null);
          }
          
          console.log('Processed data:', processedData);
          
          // Check if data has changed
          const artistsChanged = this.hasArtistsDataChanged(processedData.top_artists);
          const trendChanged = this.hasTrendDataChanged(processedData.daily_trend);
          
          // Store the current data
          this.musicData = processedData;
          
          // Update the charts only if data has changed
          this.$nextTick(() => {
            // Clear any existing timer
            if (this.chartInitTimer) {
              clearTimeout(this.chartInitTimer);
            }
            
            // Use requestAnimationFrame to wait for browser to complete rendering
            window.requestAnimationFrame(() => {
              // Use setTimeout for further delay, ensuring DOM is fully updated
              this.chartInitTimer = setTimeout(() => {
                // Only update charts if data has changed or charts don't exist
                if (this.$refs.trendChart && (trendChanged || !this.charts.trend)) {
                  this.createTrendChart();
                }
                
                if (this.$refs.artistChart && (artistsChanged || !this.charts.artist)) {
                  this.createArtistChart();
                }
              }, 200); // 200ms delay should be enough for DOM updates
            });
          });
        } else {
          const errorMsg = (response.data && response.data.message) || 'Failed to get data';
          console.error('API returned error:', errorMsg);
          this.$message.error(errorMsg);
        }
      } catch (error) {
        console.error('Failed to fetch music data:', error);
        this.$message.error('Failed to fetch music data, please check network connection');
      } finally {
        this.loading = false;
      }
    },
    handleTimeRangeChange() {
      this.queryParams.days = this.days;
      this.$message.success(`正在查询近${this.days}天的数据`);
      this.fetchMusicData();
    },
    calculateDailyAverage() {
      if (!this.musicData.total_plays || !this.queryParams.days) return 0
      return (this.musicData.total_plays / this.queryParams.days).toFixed(1)
    },
    initCharts() {
      try {
        // Clean up old chart instances to avoid memory leaks
        this.cleanupCharts();

        // Use a safe delayed execution mechanism to create charts
        window.requestAnimationFrame(() => {
          try {
            // First check if DOM elements exist
            if (this.$refs.trendChart) {
              this.createTrendChart();
            }
            
            // Use RAF to create the two charts separately, avoiding rendering blocks
            window.requestAnimationFrame(() => {
              if (this.$refs.artistChart) {
                this.createArtistChart();
              }
            });
          } catch (innerError) {
            console.error('Error during chart creation:', innerError);
            this.$message.error('Chart rendering failed, please try refreshing the page');
          }
        });
      } catch (error) {
        console.error('Error initializing charts:', error);
        this.$message.error('Chart rendering failed, please try refreshing the page');
      }
    },
    
    createTrendChart() {
      // 检查元素和数据是否存在
      if (!this.$refs.trendChart) {
        console.warn('趋势图表DOM元素不存在');
        return;
      }
      
      // 获取Canvas元素
      const canvas = this.$refs.trendChart;
      if (!canvas) {
        console.warn('趋势图表Canvas元素不存在');
        return;
      }
      
      // 检查Canvas是否已经连接到DOM
      if (!canvas.parentNode) {
        console.warn('趋势图表Canvas元素未连接到DOM');
        return;
      }
      
      // 检查Canvas的尺寸
      if (canvas.width === 0 || canvas.height === 0) {
        console.warn('趋势图表Canvas尺寸为0');
        setTimeout(() => this.createTrendChart(), 100); // 稍后重试
        return;
      }
      
      // 先销毁现有图表
      if (this.charts.trend) {
        try {
          this.charts.trend.destroy();
          this.charts.trend = null;
        } catch (e) {
          console.error('销毁趋势图表失败:', e);
        }
      }
      
      // 获取绘图上下文
      const trendCtx = canvas.getContext('2d');
      if (!trendCtx) {
        console.warn('无法获取趋势图表上下文');
        return;
      }
      
      // 在清除画布之前检查canvas的有效性
      try {
        // 清除画布
        trendCtx.clearRect(0, 0, canvas.width, canvas.height);
      } catch (e) {
        console.error('清除画布失败:', e);
        return;
      }
      
      // 检查数据有效性
      if (!this.musicData.daily_trend || this.musicData.daily_trend.length === 0) {
        // 显示无数据提示
        try {
          trendCtx.font = '16px "PingFang SC", "Microsoft YaHei", sans-serif';
          trendCtx.fillStyle = '#909399';
          trendCtx.textAlign = 'center';
          trendCtx.fillText('暂无播放趋势数据', canvas.width / 2, canvas.height / 2);
        } catch (e) {
          console.error('绘制提示文本失败:', e);
        }
        return;
      }
      
      try {
        // 准备数据
        const labels = [];
        const data = [];
        
        // 安全地提取数据
        this.musicData.daily_trend.forEach(item => {
          if (item && item.date && (item.play_count !== undefined && item.play_count !== null)) {
            labels.push(item.date);
            data.push(Number(item.play_count) || 0);
          }
        });
        
        // 如果没有有效数据，显示提示并退出
        if (labels.length === 0 || data.length === 0) {
          trendCtx.font = '16px "PingFang SC", "Microsoft YaHei", sans-serif';
          trendCtx.fillStyle = '#909399';
          trendCtx.textAlign = 'center';
          trendCtx.fillText('暂无有效播放趋势数据', canvas.width / 2, canvas.height / 2);
          return;
        }
        
        // 创建新图表
        this.charts.trend = new Chart(trendCtx, {
          type: 'line',
          data: {
            labels: labels,
            datasets: [
              {
                label: '每日播放量',
                data: data,
                borderColor: '#4680FF',
                backgroundColor: 'rgba(70, 128, 255, 0.1)',
                tension: 0.4,
                fill: true,
                borderWidth: 3,
                pointBackgroundColor: '#ffffff',
                pointBorderColor: '#4680FF',
                pointBorderWidth: 2,
                pointRadius: 4,
                pointHoverRadius: 6,
                pointHoverBackgroundColor: '#ffffff',
                pointHoverBorderColor: '#4680FF',
                pointHoverBorderWidth: 3
              }
            ]
          },
          options: {
            responsive: true,
            maintainAspectRatio: false,
            layout: {
              padding: 20
            },
            scales: {
              y: {
                beginAtZero: true,
                grid: {
                  color: 'rgba(0, 0, 0, 0.05)',
                  drawBorder: false
                },
                ticks: {
                  color: '#606266',
                  font: {
                    family: '"PingFang SC", "Microsoft YaHei", sans-serif',
                    size: 12
                  }
                },
                title: {
                  display: true,
                  text: '播放次数',
                  color: '#303133',
                  font: {
                    family: '"PingFang SC", "Microsoft YaHei", sans-serif',
                    size: 14,
                    weight: '500'
                  }
                }
              },
              x: {
                grid: {
                  color: 'rgba(0, 0, 0, 0.03)',
                  drawBorder: false
                },
                ticks: {
                  color: '#606266',
                  font: {
                    family: '"PingFang SC", "Microsoft YaHei", sans-serif',
                    size: 12
                  }
                },
                title: {
                  display: true,
                  text: '日期',
                  color: '#303133',
                  font: {
                    family: '"PingFang SC", "Microsoft YaHei", sans-serif',
                    size: 14,
                    weight: '500'
                  }
                }
              }
            },
            plugins: {
              tooltip: {
                backgroundColor: 'rgba(255, 255, 255, 0.95)',
                titleColor: '#303133',
                bodyColor: '#303133',
                borderColor: 'rgba(0, 0, 0, 0.05)',
                borderWidth: 1,
                padding: 12,
                boxPadding: 6,
                bodyFont: {
                  family: '"PingFang SC", "Microsoft YaHei", sans-serif',
                },
                titleFont: {
                  family: '"PingFang SC", "Microsoft YaHei", sans-serif',
                  weight: '600'
                },
                callbacks: {
                  label: function(context) {
                    return `播放次数: ${context.parsed.y} 次`;
                  }
                }
              },
              legend: {
                labels: {
                  boxWidth: 15,
                  padding: 20,
                  font: {
                    size: 13,
                    family: '"PingFang SC", "Microsoft YaHei", sans-serif',
                    weight: '500'
                  },
                  color: '#303133'
                }
              }
            },
            interaction: {
              mode: 'index',
              intersect: false
            },
            elements: {
              line: {
                tension: 0.4
              }
            }
          }
        });
      } catch (error) {
        console.error('创建趋势图表出错:', error);
        // 显示错误提示
        try {
          trendCtx.font = '16px "PingFang SC", "Microsoft YaHei", sans-serif';
          trendCtx.fillStyle = '#F56C6C';
          trendCtx.textAlign = 'center';
          trendCtx.fillText('图表渲染失败', canvas.width / 2, canvas.height / 2);
        } catch (e) {
          console.error('绘制错误提示失败:', e);
        }
      }
    },
    
    createArtistChart() {
      // 检查元素是否存在
      if (!this.$refs.artistChart) {
        console.warn('艺术家图表DOM元素不存在');
        return;
      }
      
      // 获取Canvas元素
      const canvas = this.$refs.artistChart;
      if (!canvas) {
        console.warn('艺术家图表Canvas元素不存在');
        return;
      }
      
      // 检查Canvas是否已经连接到DOM
      if (!canvas.parentNode) {
        console.warn('艺术家图表Canvas元素未连接到DOM');
        return;
      }
      
      // 检查Canvas的尺寸
      if (canvas.width === 0 || canvas.height === 0) {
        console.warn('艺术家图表Canvas尺寸为0');
        setTimeout(() => this.createArtistChart(), 100); // 稍后重试
        return;
      }
      
      // 先销毁现有图表
      if (this.charts.artist) {
        try {
          this.charts.artist.destroy();
          this.charts.artist = null;
        } catch (e) {
          console.error('销毁艺术家图表失败:', e);
        }
      }
      
      // 获取绘图上下文
      const artistCtx = canvas.getContext('2d');
      if (!artistCtx) {
        console.warn('无法获取艺术家图表上下文');
        return;
      }
      
      // 在清除画布之前检查canvas的有效性
      try {
        // 清除画布
        artistCtx.clearRect(0, 0, canvas.width, canvas.height);
      } catch (e) {
        console.error('清除画布失败:', e);
        return;
      }
      
      // 检查数据有效性
      if (!this.musicData.top_artists || this.musicData.top_artists.length === 0) {
        // 显示无数据提示
        try {
          artistCtx.font = '16px "PingFang SC", "Microsoft YaHei", sans-serif';
          artistCtx.fillStyle = '#909399';
          artistCtx.textAlign = 'center';
          artistCtx.fillText('暂无艺术家数据', canvas.width / 2, canvas.height / 2);
        } catch (e) {
          console.error('绘制提示文本失败:', e);
        }
        return;
      }
      
      try {
        // 首先记录原始数据，用于调试
        console.log('原始艺术家数据:', JSON.stringify(this.musicData.top_artists));
        
        // 过滤有效的艺术家数据
        const filteredArtists = this.musicData.top_artists.filter(item => {
          return item && item.artist && 
                 (typeof item.artist === 'string' || typeof item.artist === 'object') &&
                 (typeof item.artist === 'object' ? item.artist.name : item.artist.trim()) !== '' && 
                 (typeof item.artist === 'object' ? item.artist.name : item.artist.toLowerCase()) !== 'unknown' &&
                 (typeof item.artist === 'object' ? item.artist.name : item.artist) !== '未知艺术家' &&
                 (typeof item.artist === 'object' ? item.artist.name : item.artist) !== '未知';
        });
        
        // 调试过滤后的数据
        console.log('过滤后的艺术家数据:', JSON.stringify(filteredArtists));
        
        // 如果过滤后没有数据，显示提示信息
        if (filteredArtists.length === 0) {
          artistCtx.font = '16px "PingFang SC", "Microsoft YaHei", sans-serif';
          artistCtx.fillStyle = '#909399';
          artistCtx.textAlign = 'center';
          artistCtx.fillText('暂无有效艺术家数据', canvas.width / 2, canvas.height / 2);
          return;
        }
        
        // 准备数据
        const artistLabels = [];
        const artistData = [];
        
        // 安全地提取数据 - 使用正确的逻辑处理各种格式
        filteredArtists.forEach(item => {
          let artistName = '';
          let playCount = 0;
          
          // 从API获取播放次数，确保这是一个数字
          if (item.play_count !== undefined && item.play_count !== null) {
            playCount = parseInt(item.play_count, 10) || 0;
          }
          
          // 处理各种艺术家名称格式
          if (typeof item.artist === 'string') {
            const trimmed = item.artist.trim();
            // 检查是否是JSON格式的字符串
            if ((trimmed.startsWith('{') && trimmed.endsWith('}')) || 
                (trimmed.includes("'name'") || trimmed.includes('"name"'))) {
              
              // 尝试提取JSON中的名称 - 先尝试单引号格式
              const singleQuoteMatch = trimmed.match(/'name'\s*:\s*'([^']+)'/);
              if (singleQuoteMatch && singleQuoteMatch[1]) {
                artistName = singleQuoteMatch[1];
              } else {
                // 尝试双引号格式
                const doubleQuoteMatch = trimmed.match(/"name"\s*:\s*"([^"]+)"/);
                if (doubleQuoteMatch && doubleQuoteMatch[1]) {
                  artistName = doubleQuoteMatch[1];
                } else {
                  // 尝试解析JSON
                  try {
                    // 清理可能的单引号格式为双引号格式
                    const jsonString = trimmed
                      .replace(/'/g, '"')
                      .replace(/([{,]\s*)(\w+)(\s*:)/g, '$1"$2"$3'); // 确保键名有引号
                    
                    const parsedObj = JSON.parse(jsonString);
                    if (parsedObj && parsedObj.name) {
                      artistName = parsedObj.name;
                    } else {
                      // 无法解析，使用原始字符串
                      artistName = trimmed;
                    }
                  } catch (e) {
                    console.warn('JSON解析失败，使用原始字符串:', e);
                    artistName = trimmed;
                  }
                }
              }
            } else {
              // 不是JSON格式，直接使用字符串
              artistName = trimmed;
            }
          } else if (typeof item.artist === 'object' && item.artist !== null) {
            // 处理对象格式
            artistName = item.artist.name || '未知艺术家';
          } else {
            artistName = '未知艺术家';
          }
          
          // 添加到数据数组
          artistLabels.push(artistName);
          artistData.push(playCount);
          
          // 调试当前处理的艺术家数据
          console.log(`处理艺术家: ${artistName}, 播放次数: ${playCount}, 原始数据:`, item);
        });
        
        // 调试最终生成的图表数据
        console.log('图表艺术家标签:', artistLabels);
        console.log('图表播放次数数据:', artistData);
        
        // 定义颜色数组
        const colorPalette = [
          '#4680FF', '#FF6B6B', '#36C25E', '#FFB957', '#9F7FEB', '#44D7B6',
          '#FF8A48', '#6670BD', '#5BBFEA', '#F6C761', '#FF5F8A', '#2DBAA9',
          '#5271C2', '#FFB13D', '#767EE1', '#30D5C8', '#FF7051', '#4B88E5'
        ];
        
        // 确保有足够的颜色
        const backgroundColors = colorPalette.slice(0, artistLabels.length);
        const hoverBackgroundColors = backgroundColors.map(color => color);
        
        // 创建新图表，使用更简单的配置
        this.charts.artist = new Chart(artistCtx, {
          type: 'pie',
          data: {
            labels: artistLabels,
            datasets: [
              {
                data: artistData,
                backgroundColor: backgroundColors,
                hoverBackgroundColor: hoverBackgroundColors,
                borderWidth: 2,
                borderColor: '#ffffff'
              }
            ]
          },
          options: {
            responsive: true,
            maintainAspectRatio: false,
            animation: {
              animateRotate: true,
              animateScale: true,
              duration: 1800, // 动画时长
              easing: 'easeOutBounce' // 动画曲线
            },
            hover: {
              mode: 'nearest',
              animationDuration: 600
            },
            onHover: (event, chartElement) => {
              // 鼠标悬停时可自定义高亮
              event.native.target.style.cursor = chartElement[0] ? 'pointer' : 'default';
            },
            onClick: (event, chartElement) => {
              if (chartElement.length > 0) {
                const index = chartElement[0].index;
                // 弹窗显示详细信息
                window.alert(`艺术家: ${artistLabels[index]}\n播放次数: ${artistData[index]}`);
              }
            },
            plugins: {
              legend: {
                position: 'right',
                labels: {
                  font: {
                    family: '"PingFang SC", "Microsoft YaHei", sans-serif'
                  }
                }
              },
              tooltip: {
                callbacks: {
                  label: function(context) {
                    const label = context.label || '';
                    const value = context.raw || 0;
                    const total = context.dataset.data.reduce((a, b) => a + b, 0);
                    const percentage = Math.round((value / total) * 100);
                    return `${label}: ${value} 次播放 (${percentage}%)`;
                  },
                  afterLabel: function() {
                    return '点击查看详细';
                  }
                }
              }
            }
          }
        });
      } catch (error) {
        console.error('创建艺术家图表出错:', error);
        // 显示错误提示
        try {
          artistCtx.font = '16px "PingFang SC", "Microsoft YaHei", sans-serif';
          artistCtx.fillStyle = '#F56C6C';
          artistCtx.textAlign = 'center';
          artistCtx.fillText('图表渲染失败', canvas.width / 2, canvas.height / 2);
        } catch (e) {
          console.error('绘制错误提示失败:', e);
        }
      }
    },
    exportReport() {
      try {
        // 显示加载消息
        this.$message({
          message: '正在生成报表...',
          type: 'info'
        });
        
        // 创建一个工作簿对象
        const workbook = {
          SheetNames: ['音乐数据概览'],
          Sheets: {}
        };
        
        // 确保数据已加载
        if (!this.musicData || (!this.musicData.top_songs && !this.musicData.top_artists)) {
          this.$message.warning('数据尚未加载完成，请稍后再试');
          return;
        }

        // 准备表头数据
        const headers = [
          ['智能音乐系统 - 数据报表'],
          ['生成日期:', new Date().toLocaleString()],
          ['统计周期:', `过去${this.queryParams.days}天`],
          [''],
          ['1. 基本统计信息'],
          ['总播放量:', this.musicData.total_plays || 0],
          ['不同曲目数:', this.musicData.unique_songs || 0],
          ['平均每日播放:', this.calculateDailyAverage()],
          [''],
          ['2. 热门歌曲播放统计'],
          ['歌曲名称', '艺术家', '播放次数']
        ];
        
        // 添加热门歌曲数据
        const songData = this.musicData.top_songs || [];
        songData.forEach(song => {
          if (song && song.song_name) {
            headers.push([
              song.song_name || '未知歌曲',
              song.artist || '未知艺术家',
              typeof song.play_count === 'number' ? song.play_count : 0
            ]);
          }
        });
        
        // 添加空行和热门艺术家统计
        headers.push(
          [''],
          ['3. 热门艺术家播放统计'],
          ['艺术家', '播放次数']
        );
        
        // 添加热门艺术家数据
        const artistData = this.musicData.top_artists || [];
        artistData.forEach(artist => {
          if (artist && artist.artist) {
            headers.push([
              artist.artist || '未知艺术家',
              typeof artist.play_count === 'number' ? artist.play_count : 0
            ]);
          }
        });
        
        // 添加空行和日期趋势数据
        headers.push(
          [''],
          ['4. 每日播放趋势'],
          ['日期', '播放次数']
        );
        
        // 添加趋势数据
        const trendData = this.musicData.daily_trend || [];
        trendData.forEach(day => {
          if (day && day.date) {
            headers.push([
              day.date || '未知日期',
              typeof day.play_count === 'number' ? day.play_count : 0
            ]);
          }
        });
        
        try {
          // 计算每列的宽度
          const ws = {};
          const colWidths = [
            { wch: 25 }, // A
            { wch: 25 }, // B
            { wch: 15 }  // C
          ];
          
          // 设置列宽
          ws['!cols'] = colWidths;
          
          // 将数据转换为单元格格式
          const cellData = {};
          headers.forEach((row, rowIdx) => {
            row.forEach((cell, colIdx) => {
              const cellRef = String.fromCharCode(65 + colIdx) + (rowIdx + 1);
              cellData[cellRef] = { v: cell };
            });
          });
          
          // 设置表格范围
          const range = {
            s: { c: 0, r: 0 },
            e: { c: Math.max(...headers.map(row => row.length)) - 1, r: headers.length - 1 }
          };
          cellData['!ref'] = XLSX.utils.encode_range(range);
          
          // 将单元格数据添加到工作表
          workbook.Sheets['音乐数据概览'] = cellData;
          
          // 将工作簿转换为二进制数据
          const wbout = XLSX.write(workbook, { bookType: 'xlsx', type: 'binary' });
          
          // 将二进制数据转换为Blob对象
          const blob = new Blob([this.s2ab(wbout)], { type: 'application/octet-stream' });
          
          // 创建下载链接并触发下载
          const fileName = `音乐数据概览_${new Date().toISOString().split('T')[0]}.xlsx`;
          if (navigator.msSaveBlob) {
            // IE 10+
            navigator.msSaveBlob(blob, fileName);
          } else {
            const link = document.createElement('a');
            link.href = URL.createObjectURL(blob);
            link.download = fileName;
            link.click();
            URL.revokeObjectURL(link.href);
          }
          
          this.$message({
            message: '报表已导出',
            type: 'success'
          });
        } catch (excelError) {
          console.error('Excel处理出错:', excelError);
          this.$message.error('导出报表时出错，请稍后重试');
        }
      } catch (error) {
        console.error('导出报表失败:', error);
        this.$message.error('导出报表失败，请稍后重试');
      }
    },
    
    // 辅助函数：将字符串转换为ArrayBuffer
    s2ab(s) {
      const buf = new ArrayBuffer(s.length);
      const view = new Uint8Array(buf);
      for (let i = 0; i < s.length; i++) {
        view[i] = s.charCodeAt(i) & 0xFF;
      }
      return buf;
    },
    hasArtistsDataChanged(newArtists) {
      // If we don't have previous data, consider it changed
      if (!this.previousData.top_artists) {
        this.previousData.top_artists = [...newArtists];
        return true;
      }
      
      // Quick check: different array lengths
      if (newArtists.length !== this.previousData.top_artists.length) {
        this.previousData.top_artists = [...newArtists];
        return true;
      }
      
      // Compare each artist and play count
      const hasChanged = newArtists.some((artist, index) => {
        const prevArtist = this.previousData.top_artists[index];
        return (
          artist.artist !== prevArtist.artist || 
          artist.play_count !== prevArtist.play_count
        );
      });
      
      // Update previous data if changed
      if (hasChanged) {
        this.previousData.top_artists = [...newArtists];
      }
      
      return hasChanged;
    },
    
    hasTrendDataChanged(newTrend) {
      // If we don't have previous data, consider it changed
      if (!this.previousData.daily_trend) {
        this.previousData.daily_trend = [...newTrend];
        return true;
      }
      
      // Quick check: different array lengths
      if (newTrend.length !== this.previousData.daily_trend.length) {
        this.previousData.daily_trend = [...newTrend];
        return true;
      }
      
      // Compare each date and play count
      const hasChanged = newTrend.some((item, index) => {
        const prevItem = this.previousData.daily_trend[index];
        return (
          item.date !== prevItem.date || 
          item.play_count !== prevItem.play_count
        );
      });
      
      // Update previous data if changed
      if (hasChanged) {
        this.previousData.daily_trend = [...newTrend];
      }
      
      return hasChanged;
    }
  }
}
</script>

<style scoped>
.analysis-container {
  padding: 24px 16px;
  position: relative;
  margin-bottom: 80px;
  background-color: #f5f7fa;
  min-height: calc(100vh - 80px);
}

/* 页面标题区域 */
.page-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  background: linear-gradient(135deg, #1890ff, #722ed1);
  color: white;
  border-radius: 16px;
  padding: 36px 48px;
  margin-bottom: 40px;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
  overflow: hidden;
  position: relative;
  transition: all 0.3s ease;
}

.page-header:hover {
  box-shadow: 0 12px 24px rgba(0, 0, 0, 0.2);
  transform: translateY(-3px);
}

.page-header::after {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 40%;
  background: rgba(255, 255, 255, 0.12);
  transform: skewX(-25deg);
  transition: all 0.5s ease;
}

.page-header:hover::after {
  left: 45%;
  background: rgba(255, 255, 255, 0.15);
}

.header-content {
  z-index: 1;
}

.page-title {
  font-size: 32px;
  margin: 0 0 14px 0;
  font-weight: 700;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
  letter-spacing: 0.5px;
}

.page-description {
  font-size: 17px;
  margin: 0;
  opacity: 0.95;
  line-height: 1.6;
  max-width: 600px;
}

.page-actions {
  z-index: 1;
  display: flex;
  gap: 12px;
}

.page-actions .el-button {
  padding: 12px 20px;
  font-weight: 600;
}

/* 行容器样式 */
.row-container {
  margin-bottom: 35px;
  position: relative;
  z-index: 0;
}

/* 图表行特殊样式 */
.chart-row {
  margin-top: 25px;
}

/* 分隔线样式 */
.section-divider {
  display: flex;
  align-items: center;
  margin: 40px 0 15px;
  color: #606266;
}

.divider-line {
  flex-grow: 1;
  height: 1px;
  background: linear-gradient(to right, rgba(0, 0, 0, 0.02), rgba(0, 0, 0, 0.08), rgba(0, 0, 0, 0.02));
}

.divider-text {
  padding: 0 15px;
  font-size: 15px;
  font-weight: 500;
  color: #606266;
}

/* 卡片基本样式 */
.el-card {
  border-radius: 16px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  border: none;
  transform: translate3d(0, 0, 0);
  will-change: transform;
  transition: all 0.35s cubic-bezier(0.25, 0.8, 0.25, 1);
  overflow: hidden;
}

.el-card:hover {
  box-shadow: 0 12px 24px rgba(0, 0, 0, 0.12);
  transform: translateY(-4px);
  z-index: 1;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 20px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}

.card-title {
  font-size: 18px;
  font-weight: 600;
  margin-right: 12px;
  color: #303133;
  position: relative;
  padding-left: 12px;
}

.card-title::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 4px;
  height: 18px;
  background: #1890ff;
  border-radius: 2px;
}

.card-actions {
  display: flex;
  align-items: center;
}

/* 筛选器卡片样式 */
.filter-card {
  margin-bottom: 30px;
  background: linear-gradient(to right, #ffffff, #f9fbff);
}

.filter-content {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  padding: 16px 20px;
}

.filter-item {
  display: flex;
  align-items: center;
  margin-right: 24px;
  margin-bottom: 8px;
}

.filter-label {
  font-size: 15px;
  margin-right: 12px;
  font-weight: 500;
  color: #606266;
  white-space: nowrap;
}

.filter-select {
  width: 140px;
}

.filter-actions {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* 数据卡片样式 */
.data-card {
  height: 100%;
  padding: 16px;
  background: linear-gradient(135deg, #ffffff, #f5f9ff);
  border-left: 3px solid #1890ff;
}

.card-value {
  font-size: 38px;
  font-weight: 700;
  color: #1890ff;
  margin: 20px 0;
  text-shadow: 0 1px 2px rgba(24, 144, 255, 0.2);
  transition: all 0.3s ease;
}

.el-card:hover .card-value {
  transform: scale(1.05);
  color: #096dd9;
}

.card-footer {
  font-size: 14px;
  color: #606266;
  padding-top: 8px;
  border-top: 1px dashed rgba(0, 0, 0, 0.06);
}

/* 图表卡片样式 */
.chart-card {
  height: 100%;
  transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
}

.chart-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.12);
}

.chart-card .card-header {
  border-bottom: none;
  padding-bottom: 0;
}

.chart-card .card-title::before {
  background: linear-gradient(to bottom, #4680FF, #1a56e0);
  height: 20px;
}

.chart-wrapper {
  height: 350px;
  position: relative;
  padding: 20px;
}

/* 表格卡片样式 */
.table-card {
  margin-bottom: 30px;
}

.table-card .el-card__body {
  padding: 0;
}

.el-table {
  margin: 0;
  border-radius: 0;
}

.el-table th {
  background-color: #f0f5ff !important;
  padding: 16px 0;
  font-size: 15px;
  color: #1f2d3d !important;
}

.el-table td {
  padding: 14px 0;
}

.el-table--striped .el-table__row--striped td {
  background-color: #f9fafc;
}

.el-table .el-table__row:hover td {
  background-color: #ecf5ff;
}

/* 表格内容样式 */
.song-name-cell {
  display: flex;
  align-items: center;
}

.song-name {
  font-weight: 500;
  color: #303133;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.artist-cell {
  color: #606266;
  font-weight: 500;
}

.play-count-cell {
  text-align: center;
}

.play-count-cell .el-tag {
  font-weight: 500;
  min-width: 90px;
  padding: 0 12px;
  height: 32px;
  line-height: 32px;
  font-size: 14px;
}

.play-count-tag {
  display: inline-block;
  text-align: center;
}

/* 浮动操作区 */
.floating-actions {
  position: fixed;
  right: 24px;
  bottom: 24px;
  display: flex;
  align-items: center;
  z-index: 100;
}

.refresh-btn {
  border-radius: 50% !important;
  width: 52px !important;
  height: 52px !important;
  padding: 0 !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  background: linear-gradient(45deg, #1890ff, #40a9ff) !important;
  border-color: transparent !important;
  box-shadow: 0 4px 12px rgba(24, 144, 255, 0.4) !important;
  transition: all 0.3s !important;
}

.refresh-btn:hover {
  transform: translateY(-5px) scale(1.05) !important;
  box-shadow: 0 6px 16px rgba(24, 144, 255, 0.5) !important;
}

.refresh-btn .el-icon {
  font-size: 24px !important;
  margin-right: 0 !important;
}

/* 底部安全区域 */
.bottom-safe-area {
  height: 80px;
  width: 100%;
  margin-top: 30px;
}

/* 按钮样式 */
.el-button {
  border-radius: 8px;
  transition: all 0.3s;
  font-weight: 500;
}

.el-button:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
}

.el-button--primary {
  background: linear-gradient(to right, #1890ff, #40a9ff);
  border: none;
}

.el-button--primary:hover {
  background: linear-gradient(to right, #096dd9, #1890ff);
}

/* 响应式调整 */
@media (max-width: 768px) {
  .page-header {
    flex-direction: column;
    align-items: flex-start;
    padding: 24px;
  }
  
  .page-actions {
    margin-top: 20px;
    width: 100%;
  }
  
  .page-title {
    font-size: 26px;
  }
  
  .chart-wrapper {
    height: 300px;
  }
  
  .filter-content {
    flex-direction: column;
    align-items: flex-start;
  }
  
  .filter-item {
    margin-bottom: 15px;
    width: 100%;
  }
  
  .filter-select {
    flex: 1;
    width: 100%;
  }
  
  .filter-actions {
    width: 100%;
    justify-content: flex-end;
    margin-top: 8px;
  }
}
</style>